package com.hyperf.spring.boot.autoconfigure;

import cn.hutool.core.util.StrUtil;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SentinelServersConfig;
import org.redisson.config.SingleServerConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * @author lizhaoyang
 */
@Configuration
@EnableConfigurationProperties(RedissonAutoConfiguration.RedissonProperties.class)
@ConditionalOnClass(Redisson.class)
@ConditionalOnProperty(prefix = "hyperf.redisson", name = "enabled", havingValue = "true", matchIfMissing = true)
public class RedissonAutoConfiguration {

    private RedissonProperties properties;

    public RedissonAutoConfiguration(RedissonProperties properties) {
        this.properties = properties;
    }

    /**
     * 单机模式
     */
    @Bean
    @Primary
    @ConditionalOnProperty(prefix = "hyperf.redisson", name = "address")
    @ConditionalOnMissingBean
    public RedissonClient singleRedissonClient() {
        Config config = new Config();
        SingleServerConfig singleServerConfig = config.useSingleServer()
                .setAddress(properties.getAddress())
                .setDatabase(properties.getDatabase())
                .setTimeout(properties.getTimeout())
                .setConnectionPoolSize(properties.getConnectionPoolSize())
                .setConnectionMinimumIdleSize(properties.getConnectionMinimumIdleSize());
        if (StrUtil.isNotBlank(properties.getPassword())) {
            singleServerConfig.setPassword(properties.getPassword());
        }
        return Redisson.create(config);
    }

    /**
     * 哨兵模式
     */
    @Bean
    @ConditionalOnProperty(prefix = "hyperf.redisson", name = "sentinel-master-name")
    @ConditionalOnMissingBean
    public RedissonClient sentinelRedissonClient() {
        Config config = new Config();
        SentinelServersConfig sentinelServersConfig = config.useSentinelServers()
                .addSentinelAddress(properties.getSentinelAddresses())
                .setMasterName(properties.getSentinelMasterName())
                .setDatabase(properties.getDatabase())
                .setTimeout(properties.getTimeout())
                .setMasterConnectionPoolSize(properties.getMasterConnectionPoolSize())
                .setMasterConnectionMinimumIdleSize(properties.getMasterConnectionMinimumIdleSize())
                .setSlaveConnectionPoolSize(properties.getSlaveConnectionPoolSize())
                .setSlaveConnectionMinimumIdleSize(properties.getSlaveConnectionMinimumIdleSize());
        if (StrUtil.isNotBlank(properties.getPassword())) {
            sentinelServersConfig.setPassword(properties.getPassword());
        }
        return Redisson.create(config);
    }

    @Getter
    @Setter
    @NoArgsConstructor
    @ConfigurationProperties(prefix = "hyperf.redisson")
    public static class RedissonProperties {

        private boolean enabled = true;

        /**
         * 超时时间 单位:毫秒
         */
        private int timeout = 3000;

        /**
         * 哨兵模式主节点名称
         */
        private String sentinelMasterName;

        /**
         * 单机模式连接地址
         */
        private String address = "redis://127.0.0.1:6379";

        /**
         * 哨兵模式连接地址
         */
        private String[] sentinelAddresses;

        private String password;

        private int database = 0;

        private int connectionPoolSize = 10;

        private int connectionMinimumIdleSize = 5;

        private int masterConnectionPoolSize = 10;

        private int masterConnectionMinimumIdleSize = 5;

        private int slaveConnectionPoolSize = 10;

        private int slaveConnectionMinimumIdleSize = 5;
    }

}
